home *** CD-ROM | disk | FTP | other *** search
/ Developer CD Series 1996 May: Tool Chest / Developer CD Series May 1996 (Tool Chest) (Apple Computer) (1996).iso / Sample Code / AppsToGo / Kibitz / Notation.c < prev    next >
Encoding:
C/C++ Source or Header  |  1994-09-22  |  37.9 KB  |  1,638 lines  |  [TEXT/MPS ]

  1. /*
  2. ** Apple Macintosh Developer Technical Support
  3. **
  4. ** File:        notation.c
  5. ** Written by:  Eric Soldan
  6. **
  7. ** Copyright © 1990-1992 Apple Computer, Inc.
  8. ** All rights reserved. */
  9.  
  10.  
  11.  
  12. /*****************************************************************************/
  13.  
  14.  
  15.  
  16. #include "Kibitz.h"                /* Get the Kibitz includes/typedefs, etc.    */
  17. #include "KibitzCommon.h"        /* Get the stuff in common with rez.        */
  18. #include "Kibitz.protos"        /* Get the prototypes for Kibitz.            */
  19.  
  20. #ifndef __MEMORY__
  21. #include <Memory.h>
  22. #endif
  23.  
  24. #ifndef __RESOURCES__
  25. #include <Resources.h>
  26. #endif
  27.  
  28. #ifndef __TEXTEDITCONTROL__
  29. #include <TextEditControl.h>
  30. #endif
  31.  
  32. #ifndef __TOOLUTILS__
  33. #include <ToolUtils.h>
  34. #endif
  35.  
  36. #ifndef __UTILITIES__
  37. #include <Utilities.h>
  38. #endif
  39.  
  40. extern GameListHndl    gGenMovesHndl;
  41. extern Boolean        gDescriptive;
  42.  
  43. static Boolean    Descriptive(FileRecHndl frHndl, short doMoveNum, short gameIndex, StringPtr pstr);
  44. static Boolean    Algebraic(FileRecHndl frHndl, short doMoveNum, short gameIndex, StringPtr pstr);
  45. static short    IsAlgebraic  (FileRecHndl frHndl, Ptr cptr, short len, short *rfrom, short *rto, short *rpromote);
  46. static short    IsDescriptive(FileRecHndl frHndl, Ptr cptr, short len, short *rfrom, short *rto, short *rpromote);
  47. static Boolean    MoveCausesCheck(FileRecHndl game, short from, short to);
  48.  
  49.  
  50.  
  51. /*****************************************************************************/
  52. /*****************************************************************************/
  53.  
  54. #ifdef applec
  55. #pragma segment Notation
  56. #endif
  57.  
  58. /*****************************************************************************/
  59. /*****************************************************************************/
  60.  
  61.  
  62.  
  63. Boolean    AnnotateMove(FileRecHndl frHndl, short doMoveNum, short gameIndex, StringPtr pstr)
  64. {
  65.     if (gDescriptive)
  66.         return(Descriptive(frHndl, doMoveNum, gameIndex, pstr));
  67.     else
  68.         return(Algebraic(frHndl, doMoveNum, gameIndex, pstr));
  69. }
  70.  
  71.  
  72.  
  73. /*****************************************************************************/
  74.  
  75.  
  76.  
  77. static Boolean    Descriptive(FileRecHndl frHndl, short doMoveNum, short gameIndex, StringPtr pstr)
  78. {
  79.     short            from, to, piece;
  80.     short            i, r, c, rr, cc, rrr, ccc, fff, ttt, ppp;
  81.     short            color, check, ck, opFrom;
  82.     short            fromSide, fromCol, fromRow, toSide, toCol, toRow, toPiece;
  83.     short            c0, c1;
  84.     Boolean            fullDo;
  85.     GameListHndl    gameMoves;
  86.     MoveListHndl    legalMoves;
  87.  
  88.     color = WhosMove(frHndl);
  89.  
  90.     GenerateLegalMoves(frHndl);
  91.     legalMoves = (*frHndl)->doc.legalMoves;
  92.  
  93.     gameMoves = (*frHndl)->doc.gameMoves;
  94.     from = (**gameMoves)[doMoveNum].moveFrom;
  95.     to   = (**gameMoves)[doMoveNum].moveTo;
  96.  
  97.     check = MoveCausesCheck(frHndl, from, to);
  98.  
  99.     if (!from) {
  100.         GetIndString(pstr, rGameStat, to);
  101.         while (pstr[1] == ' ') BlockMove(pstr + 2, pstr + 1, --pstr[0]);
  102.         return(false);
  103.     }
  104.  
  105.     r  = from / 10;
  106.     c  = from - 10 * r - 1;
  107.     r -= 2;
  108.  
  109.     rr  = to / 10;
  110.     cc  = to - 10 * rr - 1;
  111.     rr -= 2;
  112.  
  113.     piece = (*frHndl)->doc.theBoard[from];
  114.     if (piece < 0) piece = -piece;
  115.     if (piece > BK) piece -= KSIDEPIECE;
  116.  
  117.     pstr[0] = 0;
  118.  
  119.     if (piece == KING) {
  120.         i = c - cc;
  121.         if (i == 2) {
  122.             pcpy(pstr, "\pO-O-O");
  123.             piece = EMPTY;
  124.         }
  125.         if (i == -2) {
  126.             pcpy(pstr, "\pO-O");
  127.             piece = EMPTY;
  128.         }
  129.     }
  130.  
  131.     opFrom   = 0;
  132.     fromSide = -1;
  133.     fromCol  = -1;
  134.     fromRow  = -1;
  135.  
  136.     toPiece = (*frHndl)->doc.theBoard[to];
  137.     if (toPiece < 0) toPiece = -toPiece;
  138.     if (toPiece > BK) toPiece -= KSIDEPIECE;
  139.  
  140.     if (!toPiece)
  141.         if (piece == PAWN)
  142.             if (to == (*frHndl)->doc.enPasMove)
  143.                 toPiece = PAWN;
  144.  
  145.     toSide = -1;
  146.     toCol  = -1;
  147.     toRow  = -1;
  148.  
  149.     if (piece) {
  150.         pstr[++pstr[0]] = " PNBRQK"[piece];
  151.         for (i = 0; i < (*frHndl)->doc.numLegalMoves; ++i) {
  152.             fff = (**legalMoves)[i].moveFrom;
  153.             ttt = (**legalMoves)[i].moveTo;
  154.             if (ttt == to) {
  155.                 if (fff != from) {
  156.                     ck = MoveCausesCheck(frHndl, fff, ttt);
  157.                     if (ck == check) {
  158.                         ppp = (*frHndl)->doc.theBoard[fff];
  159.                         if (ppp < 0) ppp = -ppp;
  160.                         if (ppp > BK) ppp -= KSIDEPIECE;
  161.                         if (ppp == piece) {
  162.                             fromRow = r;
  163.                             rrr  = fff / 10;
  164.                             ccc  = fff - 10 * rrr - 1;
  165.                             rrr -= 2;
  166.                             if ((rrr == r) || (opFrom)) {
  167.                                 if ((ccc != c) || (opFrom)) {
  168.                                     c0 = c;
  169.                                     if (c0 > 4) c0 = 7 - c0;
  170.                                     fromRow = r;
  171.                                     fromCol = c0;
  172.                                     c1 = ccc;
  173.                                     if (c1 > 4) c1 = 7 - c1;
  174.                                     if (c0 == c1) {
  175.                                         if (ccc != c) {
  176.                                             if (c > 4) fromSide = 1;
  177.                                             if (c < 3) fromSide = 0;
  178.                                         }
  179.                                     }
  180.                                 }
  181.                             }
  182.                             opFrom = fff;
  183.                         }
  184.                     }
  185.                 }
  186.             }
  187.         }
  188.  
  189.         for (i = 0; i < (*frHndl)->doc.numLegalMoves; ++i) {
  190.             fff = (**legalMoves)[i].moveFrom;
  191.             ttt = (**legalMoves)[i].moveTo;
  192.             ppp = (*frHndl)->doc.theBoard[fff];
  193.             if (ppp < 0) ppp = -ppp;
  194.             if (ppp > BK) ppp -= KSIDEPIECE;
  195.             if (ppp == piece) {
  196.                 ck = MoveCausesCheck(frHndl, fff, ttt);
  197.                 if (ck == check) {
  198.                     ppp = (*frHndl)->doc.theBoard[ttt];
  199.                     if (ppp < 0) ppp = -ppp;
  200.                     if (ppp > BK) ppp -= KSIDEPIECE;
  201.                     if (!ppp)
  202.                         if (piece == PAWN)
  203.                             if (ttt == (*frHndl)->doc.enPasMove)
  204.                                 ppp = PAWN;
  205.  
  206.                     if (ppp == toPiece) {
  207.                         fullDo = ((!toPiece) && (ttt == to)) ? true : false;
  208.                         rrr  = ttt / 10;
  209.                         ccc  = ttt - 10 * rrr - 1;
  210.                         rrr -= 2;
  211.                         if ((ccc != cc) && (rrr != rr)) toRow = rr;
  212.                         if (ccc == cc) {
  213.                             if ((rrr != rr) || (fullDo)) {
  214.                                 toRow = rr;
  215.                             }
  216.                         }
  217.                         if (rrr == rr) {
  218.                             if ((ccc != cc) || (fullDo)) {
  219.                                 c0 = cc;
  220.                                 if (c0 > 4) c0 = 7 - c0;
  221.                                 toRow = rr;
  222.                                 toCol = cc;
  223.                                 c1 = ccc;
  224.                                 if (c1 > 4) c1 = 7 - c1;
  225.                                 if (c0 == c1) {
  226.                                     if (ccc != cc) {
  227.                                         if (cc > 4) toSide = 1;
  228.                                         if (cc < 3) toSide = 0;
  229.                                     }
  230.                                 }
  231.                             }
  232.                         }
  233.                     }
  234.                 }
  235.             }
  236.         }
  237.  
  238.         if (opFrom) {
  239.             pstr[++pstr[0]] = '(';
  240.             if (fromSide != -1)
  241.                 pstr[++pstr[0]] = "QK"[fromSide];
  242.             if (fromCol != -1)
  243.                 pstr[++pstr[0]] = "RNBQKBNR"[fromCol];
  244.             if (fromRow != -1) {
  245.                 if (color == WHITE) fromRow = 7 - fromRow;
  246.                 pstr[++pstr[0]] = "12345678"[fromRow];
  247.             }
  248.             pstr[++pstr[0]] = ')';
  249.         }
  250.  
  251.         if (toPiece) {
  252.             pstr[++pstr[0]] = 'x';
  253.             pstr[++pstr[0]] = " PNBRQK"[toPiece];
  254.             if ((toRow == -1) && (toCol == -1) && (toSide == -1)) toPiece = 0;
  255.         }
  256.         else {
  257.             pstr[++pstr[0]] = '-';
  258.             if (toRow != -1)  toPiece = -1;
  259.             if (toCol != -1)  toPiece = -1;
  260.             if (toSide != -1) toPiece = -1;
  261.         }
  262.  
  263.         if (toPiece) {
  264.             if (toPiece > 0) pstr[++pstr[0]] = '(';
  265.             if (toSide != -1)
  266.                 pstr[++pstr[0]] = "QK"[toSide];
  267.             if (toCol != -1)
  268.                 pstr[++pstr[0]] = "RNBQKBNR"[toCol];
  269.             if (toRow != -1) {
  270.                 if (color == WHITE) toRow = 7 - toRow;
  271.                 pstr[++pstr[0]] = "12345678"[toRow];
  272.             }
  273.             if (toPiece > 0) pstr[++pstr[0]] = ')';
  274.         }
  275.     }
  276.  
  277.     if (piece == PAWN) {
  278.         to = (**gameMoves)[doMoveNum].promoteTo;
  279.         if (to) {
  280.             if (to < 0) to = -to;
  281.             pstr[++pstr[0]] = '=';
  282.             pstr[++pstr[0]] = "  NBRQ"[to];
  283.         }
  284.     }
  285.  
  286.     if (check)
  287.         pstr[++pstr[0]] = '+';
  288.  
  289.     return(doMoveNum == gameIndex - 1);
  290. }
  291.  
  292.  
  293.  
  294. /*****************************************************************************/
  295.  
  296.  
  297.  
  298. static Boolean    Algebraic(FileRecHndl frHndl, short doMoveNum, short gameIndex, StringPtr pstr)
  299. {
  300.     short            from, to, piece, extend, rowMatch, colMatch;
  301.     short            i, r, c, rr, cc, rrr, ccc, fff, ttt, ppp;
  302.     short            color, kingLoc;
  303.     GameListHndl    gameMoves;
  304.     MoveListHndl    legalMoves;
  305.  
  306.     gameMoves = (*frHndl)->doc.gameMoves;
  307.     from = (**gameMoves)[doMoveNum].moveFrom;
  308.     to   = (**gameMoves)[doMoveNum].moveTo;
  309.  
  310.     if (!from) {
  311.         GetIndString(pstr, rGameStat, to);
  312.         while (pstr[1] == ' ') BlockMove(pstr + 2, pstr + 1, --pstr[0]);
  313.         return(false);
  314.     }
  315.  
  316.     r  = from / 10;
  317.     c  = from - 10 * r - 1;
  318.     r -= 2;
  319.  
  320.     rr  = to / 10;
  321.     cc  = to - 10 * rr - 1;
  322.     rr -= 2;
  323.  
  324.     piece = (*frHndl)->doc.theBoard[from];
  325.     if (piece < 0) piece = -piece;
  326.     if (piece > BK) piece -= KSIDEPIECE;
  327.  
  328.     pstr[0] = 0;
  329.     if (piece == PAWN) {
  330.         if (c != cc) {
  331.             pstr[++pstr[0]] = "abcdefgh"[c];
  332.             pstr[++pstr[0]] = 'x';
  333.         }
  334.     }
  335.     if (piece == KING) {
  336.         i = c - cc;
  337.         if (i == 2) {
  338.             pcpy(pstr, "\pO-O-O");
  339.             piece = EMPTY;
  340.         }
  341.         if (i == -2) {
  342.             pcpy(pstr, "\pO-O");
  343.             piece = EMPTY;
  344.         }
  345.     }
  346.  
  347.     if (piece > PAWN) {
  348.         rowMatch = colMatch = extend = false;
  349.         GenerateLegalMoves(frHndl);
  350.         legalMoves = (*frHndl)->doc.legalMoves;
  351.         for (i = 0; i < (*frHndl)->doc.numLegalMoves; ++i) {
  352.             fff = (**legalMoves)[i].moveFrom;
  353.             ttt = (**legalMoves)[i].moveTo;
  354.             if ((ttt == to) && (fff != from)) {
  355.                 ppp = (*frHndl)->doc.theBoard[fff];
  356.                 if (ppp < 0) ppp = -ppp;
  357.                 if (ppp > BK) ppp -= KSIDEPIECE;
  358.                 if (ppp != piece) continue;
  359.                 rrr  = fff / 10;
  360.                 ccc  = fff - 10 * rrr - 1;
  361.                 rrr -= 2;
  362.                 extend = true;
  363.                 if (r == rrr) rowMatch = true;
  364.                 if (c == ccc) colMatch = true;
  365.             }
  366.         }
  367.         if ((extend) && (!colMatch)) rowMatch |= extend;
  368.         pstr[++pstr[0]] = "  NBRQK"[piece];
  369.         if (rowMatch)
  370.             pstr[++pstr[0]] = "abcdefgh"[c];
  371.         if (colMatch)
  372.             pstr[++pstr[0]] = "87654321"[r];
  373.         i = (*frHndl)->doc.theBoard[to];
  374.         if (!i)
  375.             if (piece == PAWN)
  376.                 if (to == (*frHndl)->doc.enPasMove)
  377.                     i = PAWN;
  378.         if ((i) && (i != OBNDS)) pstr[++pstr[0]] = 'x';
  379.     }
  380.  
  381.     if (piece) {
  382.         pstr[++pstr[0]] = "abcdefgh"[cc];
  383.         pstr[++pstr[0]] = "87654321"[rr];
  384.     }
  385.     if (piece == PAWN) {
  386.         to = (**gameMoves)[doMoveNum].promoteTo;
  387.         if (to) {
  388.             if (to < 0) to = -to;
  389.             pstr[++pstr[0]] = '=';
  390.             pstr[++pstr[0]] = "  NBRQ"[to];
  391.         }
  392.     }
  393.  
  394.     if (doMoveNum < (*frHndl)->doc.numGameMoves) {
  395.         RepositionBoard(frHndl, doMoveNum + 1, false);
  396.         kingLoc = (*frHndl)->doc.king[color = WhosMove(frHndl)].kingLoc;
  397.         if (SquareAttacked(frHndl, kingLoc, color)) pstr[++pstr[0]] = '+';
  398.         RepositionBoard(frHndl, doMoveNum, false);
  399.     }
  400.  
  401.     return(doMoveNum == gameIndex - 1);
  402. }
  403.  
  404.  
  405.  
  406. /*****************************************************************************/
  407.  
  408.  
  409.  
  410. void    MovesToOutBox(FileRecHndl frHndl, EventRecord *event)
  411. {
  412.     short        txtIndx, numGameMoves, gameIndex, startColor;
  413.     short        move, moveColor, moveNum, i, selStart, selEnd, condensed;
  414.     Boolean        needCR;
  415.     Str255        txt;
  416.     Handle        txtHndl;
  417.     TEHandle    teHndl;
  418.     WindowPtr    oldPort;
  419.  
  420.     txtHndl = NewHandle(32000);
  421.     if (!txtHndl) return;
  422.     txtIndx = 0;
  423.  
  424.     condensed = (event->modifiers & optionKey);
  425.  
  426.     numGameMoves = (*frHndl)->doc.numGameMoves;
  427.     gameIndex    = (*frHndl)->doc.gameIndex;
  428.     teHndl       = (*frHndl)->doc.message[kMessageOut];
  429.     startColor   = (*frHndl)->doc.startColor;
  430.  
  431.     txt[0] = 0;
  432.     needCR = false;
  433.     for (move = gameIndex; move < numGameMoves; ++move) {
  434.         moveColor = ((move + startColor) & 0x01);
  435.         moveNum   = ((move + startColor) / 2 + 1);
  436.         if ((needCR) && (!moveColor)) {
  437.             i = (condensed) ? 32 : 13;
  438.             (*txtHndl)[txtIndx++] = i;
  439.             needCR = false;
  440.         }
  441.         if ((!moveColor) || (move == gameIndex)) {
  442.             pcpydec(txt, i = (move / 2 + 1));
  443.             pcat(txt, "\p)  ");
  444.             if ((condensed) || (i > 9)) txt[0]--;
  445.             BlockMove(txt + 1, *txtHndl + txtIndx, txt[0]);
  446.             txtIndx += txt[0];
  447.             needCR = true;
  448.         }
  449.         if ((moveColor) && (move == gameIndex)) {
  450.             if (condensed) {
  451.                 BlockMove("...,", *txtHndl + txtIndx, 4);
  452.                 txtIndx += 4;
  453.             }
  454.             else {
  455.                 if (gDescriptive) {
  456.                     BlockMove("...             ", *txtHndl + txtIndx, 13);
  457.                     txtIndx += 13;
  458.                 } else {
  459.                     BlockMove("...      ", *txtHndl + txtIndx, 8);
  460.                     txtIndx += 8;
  461.                 }
  462.             }
  463.             needCR = true;
  464.         }
  465.         RepositionBoard(frHndl, move, false);
  466.  
  467.         AnnotateMove(frHndl, move, 0, txt);
  468.         if (move < numGameMoves - 1) {
  469.             if (condensed) {
  470.                 if (!moveColor) txt[++(txt[0])] = ',';
  471.             }
  472.             else {
  473.                 if (!moveColor) pcat(txt, "\p               ");
  474.                 if (gDescriptive) {
  475.                     if (txt[0] > 13) txt[0] = 13;
  476.                 }
  477.                 else {
  478.                     if (txt[0] > 8 ) txt[0] = 8;
  479.                 }
  480.             }
  481.         }
  482.         BlockMove(txt + 1, *txtHndl + txtIndx, txt[0]);
  483.         txtIndx += txt[0];
  484.         needCR = true;
  485.     }
  486.  
  487.     LockHandleHigh(txtHndl);
  488.     oldPort = SetFilePort(frHndl);
  489.  
  490.     CTENewUndo(CTEViewFromTE(teHndl), true);
  491.     TEDelete(teHndl);
  492.     selStart = (*teHndl)->selStart;
  493.     TEInsert(*txtHndl, txtIndx, teHndl);
  494.     selEnd = (*teHndl)->selStart;
  495.     TESetSelect(selStart, selEnd, teHndl);
  496.     TESelView(teHndl);
  497.     CTEAdjustTEBottom(teHndl);
  498.     CTEAdjustScrollValues(teHndl);
  499.     (*frHndl)->fileState.docDirty = true;
  500.  
  501.     SetPort(oldPort);
  502.     DisposeHandle(txtHndl);
  503.  
  504.     RepositionBoard(frHndl, gameIndex, false);
  505. }
  506.  
  507.  
  508.  
  509. /*****************************************************************************/
  510.  
  511.  
  512.  
  513. void    MovesFromText(FileRecHndl frHndl, Handle txtHndl, short txtLen,
  514.                       short beg, short end, Boolean slideMoves)
  515. {
  516.     WindowPtr        oldPort;
  517.     short            gameIndex, txtIndx, commentCount;
  518.     short            numUsed, nu, numLglMoves, lastChar, c0, c1, i;
  519.     short            from, to, promoteTo, f, t;
  520.     long            tick;
  521.     char            *cptr;
  522.     MoveListHndl    lglMoves;
  523.     static char        goodFirstChar[] = "Oo01abcdefghPNBRQK";
  524.  
  525.     oldPort  = SetFilePort(frHndl);
  526.     if (end == beg) end = txtLen;
  527.  
  528.     GenerateLegalMoves(frHndl);
  529.     gameIndex = (*frHndl)->doc.gameIndex;
  530.     txtIndx = beg;
  531.     commentCount = 0;
  532.  
  533.     tick = TickCount();
  534.     HLock(txtHndl);
  535.  
  536.     for (;; txtIndx += numUsed) {
  537.  
  538.         if (!commentCount) {
  539.             numLglMoves = (*frHndl)->doc.numLegalMoves;
  540.             lglMoves    = (*frHndl)->doc.legalMoves;
  541.             if (!numLglMoves) break;
  542.                 /* Can't accept any moves, as there are no legal moves. */
  543.         }
  544.  
  545.         lastChar = end - txtIndx - 1;
  546.         if (lastChar < 1) break;
  547.             /* An algebraic move is at least 2 characters. */
  548.  
  549.         cptr = *txtHndl + txtIndx;
  550.         c0 = cptr[0];
  551.         numUsed = 1;        /* Always use at least 1 character per pass. */
  552.  
  553.         if (c0 == '[') {
  554.             ++commentCount;
  555.             continue;
  556.         }
  557.  
  558.         if (c0 == ']') {
  559.             if (commentCount) --commentCount;
  560.             continue;
  561.         }
  562.  
  563.         if (commentCount) continue;
  564.  
  565.         for (i = 0; goodFirstChar[i]; ++i)
  566.             if (c0 == goodFirstChar[i]) break;
  567.         if (!goodFirstChar[i]) continue;
  568.             /* Not good first character, so check next char. */
  569.  
  570.         from = to = 0;
  571.         for (;;) {        /* Used to break from for jump purposes. */
  572.  
  573.             if (i < 3) {        /* First character is castling character... */
  574.                 if (lastChar < 2) break;
  575.                     /* Not enough characters for kside castling. */
  576.                 if (cptr[numUsed] != '-') break;        /* Isn't a castle. */
  577.                 if (cptr[numUsed + 1] != '1') {            /* Isn't a black-wins notation. */
  578.                     if (cptr[++numUsed] != c0) break;    /* Isn't a castle. */
  579.                     from = (WhosMove(frHndl)) ? 25 : 95;
  580.                     to   = from + 2;
  581.                     if (lastChar < 4) {
  582.                         ++numUsed;
  583.                         break;
  584.                     }        /* Not enough characters for qside castling, so try kside. */
  585.                     if (cptr[++numUsed] != '-') break;        /* Isn't a castle. */
  586.                     if (cptr[++numUsed] != c0) break;        /* Isn't a castle. */
  587.                     to -= 4;
  588.                     ++numUsed;
  589.                     break;        /* Try qside castle. */
  590.                 }
  591.             }
  592.  
  593.             i -= 2;
  594.             if (i < 2) {    /* May be end-of-game notation. (1-0, 1/2, 0-1) */
  595.                 if (lastChar < 2) break;
  596.                     /* Not enough characters for end-of-game notation. */
  597.                 c1 = cptr[numUsed];
  598.                 if (c1 == '-') {
  599.                     if (cptr[numUsed + 1] == ('1' - i)) to = kWhiteResigns + i;
  600.                 }
  601.                 else if (c1 == '/') {
  602.                     if (cptr[numUsed + 1] == '2') to = kDrawGame;
  603.                 }
  604.                 if (to) EndTheGame(frHndl, to);
  605.                 to = 0;
  606.                 break;        /* Done processing this character, either way. */
  607.             }
  608.  
  609.             nu = IsAlgebraic(frHndl, cptr, lastChar, &from, &to, &promoteTo);
  610.             if (from != -1) {
  611.                 numUsed += (nu - 1);
  612.                 break;
  613.             }
  614.             else {
  615.                 nu = IsDescriptive(frHndl, cptr, lastChar, &from, &to, &promoteTo);
  616.                 if (from != -1) {
  617.                     numUsed += (nu - 1);
  618.                     break;
  619.                 }
  620.             }
  621.             break;
  622.         }
  623.  
  624.         for (i = 0; i < numLglMoves; ++i) {
  625.             f = (**lglMoves)[i].moveFrom;
  626.             t = (**lglMoves)[i].moveTo;
  627.             if ((f == from) && (t == to)) break;
  628.         }
  629.         if (i < numLglMoves) {
  630.             from = (**lglMoves)[i].moveFrom;
  631.             to   = (**lglMoves)[i].moveTo;
  632.             if (slideMoves) SlideThePiece(frHndl, from, to);
  633.             MakeMove(frHndl, from, to, promoteTo);
  634.             GenerateLegalMoves(frHndl);
  635.             ImageDocument(frHndl, true);
  636.             AdjustGameSlider(frHndl);
  637.             UpdateGameStatus(frHndl);
  638.             if (tick + 30 < TickCount()) {        /* Send max 1 AppleEvent per 1/2 sec. */
  639.                 tick = TickCount();
  640.                 if ((*frHndl)->doc.twoPlayer) SendGame(frHndl, kScrolling, nil);
  641.             }
  642.         }
  643.         else {
  644.             if ((!from) && (!to)) {
  645.                 if (numUsed > 1) --numUsed;
  646.                 for (;;) {
  647.                     c0 = cptr[numUsed++];
  648.                     if (numUsed >= lastChar) break;
  649.                     if ((c0 >= 'A') && (c0 <= 'Z')) continue;
  650.                     if ((c0 >= 'a') && (c0 <= 'z')) continue;
  651.                     if ((c0 >= '0') && (c0 <= '9')) continue;
  652.                     break;
  653.                 }
  654.             }
  655.         }
  656.     }
  657.  
  658.     HUnlock(txtHndl);
  659.  
  660.     if ((*frHndl)->doc.twoPlayer) SendGame(frHndl, kResync, nil);
  661. }
  662.  
  663.  
  664.  
  665.  
  666. /*****************************************************************************/
  667.  
  668.  
  669.  
  670. void    MakeVerbose(FileRecHndl frHndl, StringPtr pstr)
  671. {
  672.     Str255                result;
  673.     Str32                piece, from, verb, to, epi;
  674.     short                i, enPas, pp, ff, tt, gameIndex;
  675.     Boolean                inParens;
  676.     GameListHndl        gameMoves;
  677.     static StringPtr    cols[] = {"\peigh,", "\pbee,", "\psea,", "\pdee,",
  678.                               "\pe,", "\pef,", "\pgee,", "\pH,"};
  679.  
  680.     if (!pstr[0]) return;
  681.  
  682.     result[0] = from[0] = to[0] = epi[0] = 0;
  683.  
  684.     enPas = false;
  685.     gameMoves = (*frHndl)->doc.gameMoves;
  686.     gameIndex = (*frHndl)->doc.gameIndex;
  687.     ff = (**gameMoves)[gameIndex].moveFrom;
  688.     tt = (**gameMoves)[gameIndex].moveTo;
  689.     pp = (*frHndl)->doc.theBoard[ff];
  690.     if (pp < 0) pp = -pp;
  691.     if (pp > BK) pp -= KSIDEPIECE;
  692.     if (pp == PAWN) {
  693.         pp = (*frHndl)->doc.theBoard[tt];
  694.         if (pp < 0) pp = -pp;
  695.         if (pp > BK) pp -= KSIDEPIECE;
  696.         if (!pp)
  697.             if (tt == (*frHndl)->doc.enPasMove)
  698.                 enPas = true;
  699.     }
  700.  
  701.     pcpy(piece, "\ppaun ");
  702.     pcpy(verb,  "\ptoo, ");
  703.  
  704.     if (pstr[i = 1] < 'Z') {
  705.         if (pstr[i] == 'O') {
  706.             ++i;
  707.             if (pstr[0] < 3) return;
  708.             pcpy(result, "\pcastle ");
  709.             if (pstr[0] < 4) {
  710.                 pcat(result, "\p king side");
  711.                 pcpy(pstr, result);
  712.                 return;
  713.             }
  714.             if (pstr[4] == '+') {
  715.                 pcat(result, "\p king side, check");
  716.                 pcpy(pstr, result);
  717.                 return;
  718.             }
  719.             pcat(result, "\p kweenn side");
  720.             if (pstr[0] >= 6) {
  721.                 if (pstr[6] == '+') pcat(result, "\p, check");
  722.                 pcpy(pstr, result);
  723.             }
  724.             pcpy(pstr, result);
  725.             return;
  726.         }
  727.  
  728.         if (pstr[i] == 'P') pcpy(piece, "\ppaun ");
  729.         if (pstr[i] == 'N') pcpy(piece, "\pknight ");
  730.         if (pstr[i] == 'B') pcpy(piece, "\pbishop ");
  731.         if (pstr[i] == 'R') pcpy(piece, "\prook ");
  732.         if (pstr[i] == 'Q') pcpy(piece, "\pkweenn ");
  733.         if (pstr[i] == 'K') pcpy(piece, "\pking ");
  734.         ++i;
  735.     }
  736.  
  737.     if (i > pstr[0]) return;
  738.  
  739.     if (gDescriptive) {
  740.         inParens = false;
  741.         for (i = 1; i <= pstr[0]; ++i) {
  742.             switch (pstr[i]) {
  743.                 case 'P':
  744.                     pcat(result, "\p pawn ");
  745.                     break;
  746.                 case 'N':
  747.                     pcat(result, "\p knight ");
  748.                     break;
  749.                 case 'B':
  750.                     pcat(result, "\p bishop ");
  751.                     break;
  752.                 case 'R':
  753.                     pcat(result, "\p rook ");
  754.                     break;
  755.                 case 'Q':
  756.                     pcat(result, "\p kweenn ");
  757.                     break;
  758.                 case 'K':
  759.                     pcat(result, "\p king ");
  760.                     break;
  761.                 case '1':
  762.                 case '2':
  763.                 case '3':
  764.                 case '4':
  765.                 case '5':
  766.                 case '6':
  767.                 case '7':
  768.                 case '8':
  769.                     pcatchr(result, pstr[i], 1);
  770.                     if (inParens)
  771.                         pcatchr(result, ',', 1);
  772.                     pcatchr(result, ' ', 1);
  773.                     inParens = false;
  774.                     break;
  775.                 case '(':
  776.                     inParens = true;
  777.                     pcat(result, "\p, at, ");
  778.                     break;
  779.                 case ')':
  780.                     inParens = false;
  781.                     break;
  782.                 case '-':
  783.                     pcat(result,  "\p too ");
  784.                     break;
  785.                 case 'x':
  786.                     pcat(result, "\p takes ");
  787.                     break;
  788.                 case '=':
  789.                     if (enPas) {
  790.                         pcat(result, "\p, en paw saunt ");
  791.                         enPas = false;
  792.                     }
  793.                     pcat(result, "\p, promote too ");
  794.                     break;
  795.                 case '+':
  796.                     if (enPas) {
  797.                         pcat(result, "\p, en paw saunt ");
  798.                         enPas = false;
  799.                     }
  800.                     pcat(result, "\p, check");
  801.                     break;
  802.             }
  803.         }
  804.  
  805.         if (enPas) {
  806.             pcat(result, "\p, en paw saunt ");
  807.             enPas = false;
  808.         }
  809.  
  810.         pcpy(pstr, result);
  811.         return;
  812.     }
  813.  
  814.     if ((pstr[i] >= '1') && (pstr[i] <= '8')) {
  815.         if (pstr[0] > (i + 1)) {
  816.             pcpy(from, "\pat, ");
  817.             pcatchr(from, pstr[i++], 1);
  818.             pcat(from, "\p, ");
  819.         }
  820.     }
  821.  
  822.     if ((pstr[i] >= 'a') && (pstr[i] <= 'h')) {
  823.         if (pstr[0] > (i + 1)) {
  824.             if ((pstr[i + 1] < '1') || (pstr[i + 1] > '8')) {
  825.                 pcpy(from, "\pat, ");
  826.                 pcat(from, cols[pstr[i++] - 'a']);
  827.                 pcatchr(from, ' ', 1);
  828.             }
  829.         }
  830.     }
  831.  
  832.     if (i > pstr[0]) return;
  833.  
  834.     if (pstr[i] == 'x') {
  835.         pcpy(verb, "\ptakes, ");
  836.         ++i;
  837.     }
  838.  
  839.     if (i > pstr[0]) return;
  840.  
  841.     if ((pstr[i] >= 'a') && (pstr[i] <= 'h')) {
  842.         pcat(to, cols[pstr[i++] - 'a']);
  843.         pcatchr(to, ' ', 1);
  844.     }
  845.  
  846.     if (i > pstr[0]) return;
  847.  
  848.     if ((pstr[i] >= '1') && (pstr[i] <= '8')) {
  849.         pcatchr(to, pstr[i++], 1);
  850.         pcatchr(to, ' ', 1);
  851.     }
  852.  
  853.     if (i <= pstr[0]) {
  854.         if (pstr[i] == '=') {
  855.             pcat(epi, "\p, promote too ");
  856.             if (++i > pstr[0]) return;
  857.             if (pstr[i] == 'N') pcat(epi, "\pknight ");
  858.             if (pstr[i] == 'B') pcat(epi, "\pbishop ");
  859.             if (pstr[i] == 'R') pcat(epi, "\prook ");
  860.             if (pstr[i] == 'Q') pcat(epi, "\pkweenn ");
  861.             ++i;
  862.         }
  863.     }
  864.  
  865.     if (i <= pstr[0]) {
  866.         if (pstr[i] == '+')
  867.             pcat(epi, "\p, check");
  868.     }
  869.  
  870.     pcpy(pstr, piece);
  871.     pcat(pstr, from);
  872.     pcat(pstr, verb);
  873.     pcat(pstr, to);
  874.     pcat(pstr, epi);
  875. }
  876.  
  877.  
  878.  
  879. /*****************************************************************************/
  880.  
  881.  
  882.  
  883. void    SayTheMove(FileRecHndl frHndl)
  884. {
  885.     Handle    txt;
  886.     Str255    pstr;
  887.     short    i;
  888.     Boolean    move;
  889.  
  890.     if (!(*frHndl)->doc.doSpeech) return;
  891.  
  892.     MakeMove(frHndl, -1, 0, 0);
  893.  
  894.     i = (*frHndl)->doc.gameIndex;
  895.     if (gDescriptive)
  896.         move = Descriptive(frHndl, i, i + 1, pstr);
  897.     else
  898.         move = Algebraic(frHndl, i, i + 1, pstr);
  899.     if (move) MakeVerbose(frHndl, pstr);
  900.  
  901.     MakeMove(frHndl, 1, 0, 0);
  902.  
  903.     switch (i = GameStatus(frHndl)) {
  904.         case kYouWin:
  905.         case kYouLose:
  906.             pcat(pstr, "\p mate");
  907.             break;
  908.     }
  909.  
  910.     txt = NewHandle(pstr[0]);
  911.     BlockMove(pstr + 1, *txt, pstr[0]);
  912.     SayText(nil, txt, (*frHndl)->doc.theVoice);
  913.     DisposeHandle(txt);
  914. }
  915.  
  916.  
  917.  
  918. /*****************************************************************************/
  919.  
  920.  
  921.  
  922. static short    IsAlgebraic(FileRecHndl frHndl, Ptr cptr, short lastChar, short *rfrom, short *rto, short *rpromote)
  923. {
  924.     short            numUsed, numLglMoves, c0, c1, i, j, k, numMatch;
  925.     short            from, to, fromRow, fromCol, toRow, toCol, piece, f, t, r, c;
  926.     Boolean            take, check;
  927.     MoveListHndl    lglMoves;
  928.     static char        goodFirstChar[] = "abcdefghPNBRQK";
  929.  
  930.     *rfrom = *rto = -1;                        /* Not algebraic move flag. */
  931.     *rpromote = QUEEN;
  932.  
  933.     if (lastChar < 1) return(1);            /* An algebraic move is at least 2 characters. */
  934.  
  935.     c0 = cptr[0];
  936.     numUsed = 1;                            /* Always use at least 1 character per pass. */
  937.  
  938.     numLglMoves = (*frHndl)->doc.numLegalMoves;
  939.     lglMoves    = (*frHndl)->doc.legalMoves;
  940.  
  941.     for (i = 0; goodFirstChar[i]; ++i)
  942.         if (c0 == goodFirstChar[i]) break;
  943.  
  944.     if (!goodFirstChar[i]) return(numUsed);        /* Just used first char. */
  945.  
  946.     fromRow = fromCol = -1;
  947.     toRow   = toCol   = -1;
  948.     from = to = 0;
  949.     take = check = false;
  950.         /* From may be square or piece. */
  951.         /* To will be square. */
  952.         /* If to stays 0, then to = from, and from = PAWN.  More on this later. */
  953.  
  954.     for (;;) {        /* Used to break from for jump purposes. */
  955.  
  956.         if (i < 8) {        /* It is probably a pawn move.  The form is one of   */
  957.                             /* the following: e4, dxe, dxe4, d3xe4, d3e4, d3-e4. */
  958.                             /* Due to this, it can't be decided yet as to        */
  959.                             /* whether we are looking at the from or the to      */
  960.                             /* location.                                         */
  961.  
  962.             from = PAWN;
  963.             fromCol = i;    /* Might end up the toCol, so keep this in mind. */
  964.             c1 = cptr[numUsed];
  965.             if ((c1 >= '1') && (c1 <= '8')) {
  966.                 fromRow = 7 - (c1 - '1');    /* Might end up the toRow. */
  967.                 if (++numUsed > lastChar) break;
  968.                 c1 = cptr[numUsed];
  969.             }
  970.             if ((c1 == 'x') || (c1 == 'X')) take = true;
  971.             if ((take) || (c1 == '-')) {
  972.                 if (++numUsed > lastChar) break;
  973.                 c0 = cptr[numUsed];
  974.                 if ((c0 < 'a') || (c0 > 'h')) break;
  975.                 toCol = c0 - 'a';
  976.                 if (numUsed >= lastChar) break;
  977.                 else {
  978.                     c1 = cptr[++numUsed];
  979.                     if ((c1 >= '1') && (c1 <= '8')) {
  980.                         toRow = 7 - (c1 - '1');
  981.                         to = 10 * toRow + toCol + START_IBNDS;
  982.                         from = PAWN;        /* Assume it is a pawn move. */
  983.                         if ((fromRow != -1) && (fromCol != -1))
  984.                             from = 10 * fromRow + fromCol + START_IBNDS;
  985.                                 /* Move is of form d3-e4, so it doesn't have to be a pawn. */
  986.                         break;
  987.                     }
  988.                 }
  989.             }
  990.             else {
  991.                 if (fromRow != -1) {            /* Of the form e4. */
  992.                     if ((c1 < 'a') || (c1 > 'h')) {
  993.                         from = PAWN;
  994.                         to = 10 * fromRow + fromCol + START_IBNDS;
  995.                         fromRow = fromCol = -1;        /* No hint of where from. */
  996.                     }
  997.                     else {
  998.                         toCol = c1 - 'a';
  999.                         c0 = c1;
  1000.                         if (++numUsed > lastChar) break;
  1001.                         c1 = cptr[numUsed];
  1002.                         if ((c1 >= '1') && (c1 <= '8')) {
  1003.                             toRow = 7 - (c1 - '1');
  1004.                             to = 10 * toRow + toCol + START_IBNDS;
  1005.                             from = PAWN;        /* Assume it is a pawn move. */
  1006.                             if ((fromRow != -1) && (fromCol != -1))
  1007.                                 from = 10 * fromRow + fromCol + START_IBNDS;
  1008.                                     /* Move is of form d3e4, so it doesn't have to be a pawn. */
  1009.                             ++numUsed;
  1010.                             break;
  1011.                         }
  1012.                     }
  1013.                 }
  1014.                 break;
  1015.             }
  1016.         }
  1017.  
  1018.         else from = i - 7;        /* Remember which kind of piece. */
  1019.  
  1020.         c0 = cptr[numUsed];
  1021.  
  1022.         if (c0 == '(') {    /* Parens are optional -- just skip them. */
  1023.             if (++numUsed > lastChar) break;
  1024.             c0 = cptr[numUsed];
  1025.         }
  1026.  
  1027.         if ((c0 >= 'a') && (c0 <= 'h')) {
  1028.             fromCol = c0 - 'a';
  1029.             if (++numUsed > lastChar) break;
  1030.             c0 = cptr[numUsed];
  1031.         }
  1032.         if ((c0 >= 'a') && (c0 <= 'h')) {
  1033.             toCol = c0 - 'a';
  1034.             if (++numUsed > lastChar) break;
  1035.             c1 = cptr[numUsed];
  1036.             if ((c1 >= '1') && (c1 <= '8')) {
  1037.                 toRow = 7 - (c1 - '1');
  1038.                 to = 10 * toRow + toCol + START_IBNDS;
  1039.                 ++numUsed;
  1040.             }
  1041.             break;
  1042.         }
  1043.         if ((c0 >= '1') && (c0 <= '8')) {
  1044.             fromRow = 7 - (c0 - '1');
  1045.             if (++numUsed > lastChar) break;
  1046.             c0 = cptr[numUsed];
  1047.         }
  1048.  
  1049.         if (c0 == ')') {    /* Parens are optional -- just skip them. */
  1050.             if (++numUsed > lastChar) break;
  1051.             c0 = cptr[numUsed];
  1052.         }
  1053.  
  1054.         if ((c0 == 'x') || (c0 == 'X')) take = true;
  1055.         if ((take) || (c0 == '-')) {
  1056.             if ((c0 == 'x') || (c0 == 'X') || (c0 == '-')) ++numUsed;
  1057.             if (numUsed > lastChar) break;
  1058.             c0 = cptr[numUsed];
  1059.         }
  1060.  
  1061.         if ((c0 >= 'a') && (c0 <= 'h')) {
  1062.             toCol = c0 - 'a';
  1063.             if (++numUsed > lastChar) break;
  1064.             c1 = cptr[numUsed];
  1065.             if ((c1 >= '1') && (c1 <= '8')) {
  1066.                 toRow = 7 - (c1 - '1');
  1067.                 to = 10 * toRow + toCol + START_IBNDS;
  1068.                 ++numUsed;
  1069.             }
  1070.             break;
  1071.         }
  1072.         else {
  1073.             if ((fromRow != -1) && (fromCol != -1)) {
  1074.                 to = 10 * fromRow + fromCol + START_IBNDS;
  1075.                 fromRow = fromCol = -1;        /* No hint of where from. */
  1076.             }
  1077.             break;
  1078.         }
  1079.  
  1080.         break;
  1081.     }
  1082.  
  1083.     if ((!to) && (toRow == -1) && (toCol == -1)) {
  1084.         if ((fromRow != -1) && (fromCol != -1)) {
  1085.             to = 10 * fromRow + fromCol + START_IBNDS;
  1086.             fromRow = fromCol = -1;
  1087.         }
  1088.     }
  1089.  
  1090.     if ((to) || (toRow > -1) || (toCol > -1)) {
  1091.         if (numUsed < lastChar) {
  1092.             c0 = cptr[numUsed]; 
  1093.             if (c0 == '=') {
  1094.                 if (++numUsed <= lastChar) {
  1095.                     c0 = cptr[numUsed];
  1096.                     if (c0 == 'N') *rpromote = KNIGHT;
  1097.                     if (c0 == 'B') *rpromote = BISHOP;
  1098.                     if (c0 == 'R') *rpromote = ROOK;
  1099.                     if ((c0 == 'N') || (c0 == 'B') || (c0 == 'R') || (c0 == 'Q'))
  1100.                         if (++numUsed <= lastChar)
  1101.                             c0 = cptr[numUsed];
  1102.                 }
  1103.             }
  1104.         }
  1105.     }
  1106.     if (c0 == '+') {
  1107.          check = true;
  1108.         if (++numUsed <= lastChar) c0 = cptr[numUsed];
  1109.     }
  1110.  
  1111.     for (numMatch = 0, j = 0; j < 2; ++j) {
  1112.         for (i = 0; i < numLglMoves; ++i) {
  1113.             f = (**lglMoves)[i].moveFrom;
  1114.             t = (**lglMoves)[i].moveTo;
  1115.  
  1116.             if (to >= START_IBNDS) {            /* If we have a fully formed to...               */
  1117.                 if (to != t) continue;            /* If to is different than this move, next move. */
  1118.             }
  1119.             else {
  1120.                 if (to) {
  1121.                     piece = (*frHndl)->doc.theBoard[t];
  1122.                     if (piece < 0) piece = -piece;
  1123.                     if (piece > BK) piece -= KSIDEPIECE;
  1124.                     if (piece != to) continue;
  1125.                 }
  1126.                 if ((!to) && (toRow == -1) && (toCol == -1)) continue;
  1127.                 r = (t - START_IBNDS) / 10;
  1128.                 c = t - START_IBNDS - 10 * r;
  1129.                 if (toRow == -1) r = -1;
  1130.                 if (toCol == -1) c = -1;
  1131.                 if ((toRow != r) || (toCol != c)) continue;
  1132.                 if (take) {
  1133.                     k = (**lglMoves)[i].moveTo;
  1134.                     if (!(*frHndl)->doc.theBoard[k]) continue;
  1135.                 }
  1136.             }
  1137.  
  1138.             if (from >= START_IBNDS) {
  1139.                 if (from == f) {
  1140.                     if (!j) ++numMatch;
  1141.                     else {
  1142.                         if (numMatch < 2) break;
  1143.                         if (MoveCausesCheck(frHndl, f, t) == check) break;
  1144.                     }
  1145.                 }
  1146.                 continue;
  1147.             }
  1148.             piece = (*frHndl)->doc.theBoard[f];
  1149.             if (piece < 0) piece = -piece;
  1150.             if (piece > BK) piece -= KSIDEPIECE;
  1151.             if (piece == from) {
  1152.                 r = (f - START_IBNDS) / 10;
  1153.                 c = f - START_IBNDS - 10 * r;
  1154.                 if (fromRow == -1) r = -1;
  1155.                 if (fromCol == -1) c = -1;
  1156.                 if ((fromRow == r) && (fromCol == c)) {
  1157.                     if (!j) ++numMatch;
  1158.                     else {
  1159.                         if (numMatch < 2) break;
  1160.                         if (MoveCausesCheck(frHndl, f, t) == check) break;
  1161.                     }
  1162.                 }
  1163.             }
  1164.         }
  1165.     }
  1166.  
  1167.     if (i < numLglMoves) {
  1168.         *rfrom = (**lglMoves)[i].moveFrom;
  1169.         *rto   = (**lglMoves)[i].moveTo;
  1170.     };
  1171.  
  1172.     return(numUsed);
  1173. }
  1174.  
  1175.  
  1176.  
  1177. /*****************************************************************************/
  1178.  
  1179.  
  1180.  
  1181. static short    IsDescriptive(FileRecHndl frHndl, Ptr cptr, short lastChar, short *rfrom, short *rto, short *rpromote)
  1182. {
  1183.     short            numUsed, numLglMoves, c0, i, j, k, numMatch;
  1184.     short            from, to, fromRow, fromCol, fromCol2, toRow, toCol, toCol2;
  1185.     short            piece, f, t, r, c, color;
  1186.     Boolean            take, check;
  1187.     MoveListHndl    lglMoves;
  1188.     static char        goodPieceChar[] = "PNBRQK";
  1189.     static char        goodFTChar[]    = "PNBRQK12345678";
  1190.  
  1191.     *rfrom = *rto = -1;                        /* Not algebraic move flag. */
  1192.     *rpromote = QUEEN;
  1193.  
  1194.     color = WhosMove(frHndl);                /* Who's move it is. */
  1195.  
  1196.     if (lastChar < 1) return(1);            /* An algebraic move is at least 2 characters. */
  1197.  
  1198.     c0 = cptr[0];
  1199.     numUsed = 1;                            /* Always use at least 1 character per pass. */
  1200.  
  1201.     numLglMoves = (*frHndl)->doc.numLegalMoves;
  1202.     lglMoves    = (*frHndl)->doc.legalMoves;
  1203.  
  1204.     for (i = 0; goodPieceChar[i]; ++i) if (c0 == goodPieceChar[i]) break;
  1205.     if (!goodPieceChar[i]) return(numUsed);        /* Just used first char. */
  1206.  
  1207.     fromRow = fromCol = fromCol2 = -1;
  1208.     toRow   = toCol   = toCol2   = -1;
  1209.     from = to = 0;
  1210.     take = check = false;
  1211.         /* From may be square or piece. */
  1212.         /* To will be square. */
  1213.         /* If to stays 0, then to = from, and from = PAWN.  More on this later. */
  1214.  
  1215.     for (;;) {        /* Used to break from for jump purposes. */
  1216.  
  1217.         from = i + 1;        /* Remember which kind of piece. */
  1218.  
  1219.         c0 = cptr[numUsed];
  1220.         if (from == QUEEN) {
  1221.             if (c0 == 'R')
  1222.                 from = ROOK;
  1223.             if (c0 == 'N')
  1224.                 from = KNIGHT;
  1225.             if (c0 == 'B')
  1226.                 from = BISHOP;
  1227.             if (from != QUEEN)
  1228.                 if (++numUsed > lastChar)
  1229.                     return(numUsed);
  1230.             c0 = cptr[numUsed];
  1231.         }
  1232.         if (from == KING) {
  1233.             if (c0 == 'R')
  1234.                 from = ROOK + KSIDEPIECE;
  1235.             if (c0 == 'N')
  1236.                 from = KNIGHT + KSIDEPIECE;
  1237.             if (c0 == 'B')
  1238.                 from = BISHOP + KSIDEPIECE;
  1239.             if (from != KING)
  1240.                 if (++numUsed > lastChar)
  1241.                     return(numUsed);
  1242.             c0 = cptr[numUsed];
  1243.         }
  1244.  
  1245.         if (c0 == '(') {
  1246.             if (++numUsed > lastChar) return(numUsed);
  1247.             c0 = cptr[numUsed];
  1248.  
  1249.             for (j = 1; goodFTChar[j]; ++j) if (c0 == goodFTChar[j]) break;
  1250.             if (!goodFTChar[j]) return(numUsed);        /* Just used first char. */
  1251.  
  1252.             if (c0 == 'R') {
  1253.                 fromCol  = 0;
  1254.                 fromCol2 = 7;
  1255.             }
  1256.             if (c0 == 'N') {
  1257.                 fromCol  = 1;
  1258.                 fromCol2 = 6;
  1259.             }
  1260.             if (c0 == 'B') {
  1261.                 fromCol  = 2;
  1262.                 fromCol2 = 5;
  1263.             }
  1264.             if (c0 == 'Q') {
  1265.                 fromCol  = 3;
  1266.                 fromCol2 = 3;
  1267.             }
  1268.             if (c0 == 'K') {
  1269.                 fromCol  = 4;
  1270.                 fromCol2 = 4;
  1271.             }
  1272.             if (fromCol != -1) {
  1273.                 if (++numUsed > lastChar) return(numUsed);
  1274.                 c0 = cptr[numUsed];
  1275.             }
  1276.  
  1277.             if (c0 == 'R') {
  1278.                 if (fromCol == 3) {
  1279.                     fromCol  = 0;
  1280.                     fromCol2 = 0;
  1281.                 }
  1282.                 if (fromCol == 4) {
  1283.                     fromCol  = 7;
  1284.                     fromCol2 = 7;
  1285.                 }
  1286.                 if (fromCol != fromCol2)  return(numUsed);
  1287.                 if (++numUsed > lastChar) return(numUsed);
  1288.                 c0 = cptr[numUsed];
  1289.             }
  1290.             if (c0 == 'N') {
  1291.                 if (fromCol == 3) {
  1292.                     fromCol  = 1;
  1293.                     fromCol2 = 1;
  1294.                 }
  1295.                 if (fromCol == 4) {
  1296.                     fromCol  = 6;
  1297.                     fromCol2 = 6;
  1298.                 }
  1299.                 if (fromCol != fromCol2)  return(numUsed);
  1300.                 if (++numUsed > lastChar) return(numUsed);
  1301.                 c0 = cptr[numUsed];
  1302.             }
  1303.             if (c0 == 'B') {
  1304.                 if (fromCol == 3) {
  1305.                     fromCol  = 2;
  1306.                     fromCol2 = 2;
  1307.                 }
  1308.                 if (fromCol == 4) {
  1309.                     fromCol  = 5;
  1310.                     fromCol2 = 5;
  1311.                 }
  1312.                 if (fromCol != fromCol2)  return(numUsed);
  1313.                 if (++numUsed > lastChar) return(numUsed);
  1314.                 c0 = cptr[numUsed];
  1315.             }
  1316.  
  1317.             if ((c0 >= '1') && (c0 <= '8')) {
  1318.                 fromRow = '8' - c0;
  1319.                 if (color == BLACK) fromRow = 7 - fromRow;
  1320.                 if (++numUsed > lastChar) return(numUsed);
  1321.                 c0 = cptr[numUsed];
  1322.             }
  1323.  
  1324.             if (c0 == ')') {
  1325.                 if (++numUsed > lastChar) return(numUsed);
  1326.                 c0 = cptr[numUsed];
  1327.             }
  1328.         }
  1329.  
  1330.         if ((c0 == 'x') || (c0 == 'X')) {
  1331.             take = true;
  1332.             if (++numUsed > lastChar) return(numUsed);
  1333.             c0 = cptr[numUsed];
  1334.             for (i = 0; goodPieceChar[i]; ++i) if (c0 == goodPieceChar[i]) break;
  1335.             if (!goodPieceChar[i]) return(numUsed);
  1336.             to = i + 1;
  1337.             if (++numUsed > lastChar) break;
  1338.             c0 = cptr[numUsed];
  1339.  
  1340.             switch (to) {
  1341.                 case ROOK:
  1342.                     if (c0 == 'P') {
  1343.                         to     = PAWN;
  1344.                         toCol  = 0;
  1345.                         toCol2 = 7;
  1346.                         if (++numUsed > lastChar) break;
  1347.                         c0 = cptr[numUsed];
  1348.                     }
  1349.                     break;
  1350.                 case KNIGHT:
  1351.                     if (c0 == 'P') {
  1352.                         to     = PAWN;
  1353.                         toCol  = 1;
  1354.                         toCol2 = 6;
  1355.                         if (++numUsed > lastChar) break;
  1356.                         c0 = cptr[numUsed];
  1357.                     }
  1358.                     break;
  1359.                 case BISHOP:
  1360.                     if (c0 == 'P') {
  1361.                         to     = PAWN;
  1362.                         toCol  = 2;
  1363.                         toCol2 = 5;
  1364.                         if (++numUsed > lastChar) break;
  1365.                         c0 = cptr[numUsed];
  1366.                     }
  1367.                     break;
  1368.                 case QUEEN:
  1369.                     if (c0 == 'R')
  1370.                         to = ROOK;
  1371.                     if (c0 == 'N')
  1372.                         to = KNIGHT;
  1373.                     if (c0 == 'B')
  1374.                         to = BISHOP;
  1375.                     if (to != QUEEN)
  1376.                         if (++numUsed > lastChar)
  1377.                             break;
  1378.                     c0 = cptr[numUsed];
  1379.                     if (c0 == 'P') {
  1380.                         to     = PAWN;
  1381.                         toCol  = 3;
  1382.                         toCol2 = 3;
  1383.                         if (++numUsed > lastChar) break;
  1384.                         c0 = cptr[numUsed];
  1385.                     }
  1386.                     break;
  1387.                 case KING:
  1388.                     if (c0 == 'R')
  1389.                         to = ROOK + KSIDEPIECE;
  1390.                     if (c0 == 'N')
  1391.                         to = KNIGHT + KSIDEPIECE;
  1392.                     if (c0 == 'B')
  1393.                         to = BISHOP + KSIDEPIECE;
  1394.                     if (to != KING)
  1395.                         if (++numUsed > lastChar)
  1396.                             break;
  1397.                     c0 = cptr[numUsed];
  1398.                     if (c0 == 'P') {
  1399.                         to     = PAWN;
  1400.                         toCol  = 4;
  1401.                         toCol2 = 4;
  1402.                         if (++numUsed > lastChar) break;
  1403.                         c0 = cptr[numUsed];
  1404.                     }
  1405.                     break;
  1406.             }
  1407.             if (numUsed > lastChar) break;
  1408.         }
  1409.  
  1410.         if ((c0 == '-') || (c0 == '(')) {
  1411.             if (++numUsed > lastChar) return(numUsed);
  1412.             c0 = cptr[numUsed];
  1413.  
  1414.             if (c0 == '-') {
  1415.                 for (j = 1; goodPieceChar[j]; ++j) if (c0 == goodPieceChar[j]) break;
  1416.                 if (!goodPieceChar[j]) return(numUsed);        /* Just used first char. */
  1417.             }
  1418.             if (c0 == '(') {
  1419.                 for (j = 1; goodFTChar[j]; ++j) if (c0 == goodFTChar[j]) break;
  1420.                 if (!goodFTChar[j]) return(numUsed);        /* Just used first char. */
  1421.             }
  1422.  
  1423.             if (c0 == 'R') {
  1424.                 toCol  = 0;
  1425.                 toCol2 = 7;
  1426.             }
  1427.             if (c0 == 'N') {
  1428.                 toCol  = 1;
  1429.                 toCol2 = 6;
  1430.             }
  1431.             if (c0 == 'B') {
  1432.                 toCol  = 2;
  1433.                 toCol2 = 5;
  1434.             }
  1435.             if (c0 == 'Q') {
  1436.                 toCol  = 3;
  1437.                 toCol2 = 3;
  1438.             }
  1439.             if (c0 == 'K') {
  1440.                 toCol  = 4;
  1441.                 toCol2 = 4;
  1442.             }
  1443.             if (toCol != -1) {
  1444.                 if (++numUsed > lastChar) return(numUsed);
  1445.                 c0 = cptr[numUsed];
  1446.             }
  1447.  
  1448.             if (c0 == 'R') {
  1449.                 if (toCol == 3) {
  1450.                     toCol  = 0;
  1451.                     toCol2 = 0;
  1452.                 }
  1453.                 if (toCol == 4) {
  1454.                     toCol  = 7;
  1455.                     toCol2 = 7;
  1456.                 }
  1457.                 if (toCol != toCol2)  return(numUsed);
  1458.                 if (++numUsed > lastChar) return(numUsed);
  1459.                 c0 = cptr[numUsed];
  1460.             }
  1461.             if (c0 == 'N') {
  1462.                 if (toCol == 3) {
  1463.                     toCol  = 1;
  1464.                     toCol2 = 1;
  1465.                 }
  1466.                 if (toCol == 4) {
  1467.                     toCol  = 6;
  1468.                     toCol2 = 6;
  1469.                 }
  1470.                 if (toCol != toCol2)  return(numUsed);
  1471.                 if (++numUsed > lastChar) return(numUsed);
  1472.                 c0 = cptr[numUsed];
  1473.             }
  1474.             if (c0 == 'B') {
  1475.                 if (toCol == 3) {
  1476.                     toCol  = 2;
  1477.                     toCol2 = 2;
  1478.                 }
  1479.                 if (toCol == 4) {
  1480.                     toCol  = 5;
  1481.                     toCol2 = 5;
  1482.                 }
  1483.                 if (toCol != toCol2)  return(numUsed);
  1484.                 if (++numUsed > lastChar) return(numUsed);
  1485.                 c0 = cptr[numUsed];
  1486.             }
  1487.  
  1488.             if ((c0 >= '1') && (c0 <= '8')) {
  1489.                 toRow = '8' - c0;
  1490.                 if (color == BLACK) toRow = 7 - toRow;
  1491.                 if (++numUsed > lastChar) break;
  1492.                 c0 = cptr[numUsed];
  1493.             }
  1494.  
  1495.             if (c0 == ')') {
  1496.                 if (++numUsed > lastChar) break;
  1497.                 c0 = cptr[numUsed];
  1498.             }
  1499.         }
  1500.  
  1501.         break;
  1502.     }
  1503.  
  1504.     if ((to) || (toRow > -1) || (toCol > -1)) {
  1505.         if (numUsed < lastChar) {
  1506.             c0 = cptr[numUsed]; 
  1507.             if (c0 == '=') {
  1508.                 if (++numUsed <= lastChar) {
  1509.                     c0 = cptr[numUsed];
  1510.                     if (c0 == 'N') *rpromote = KNIGHT;
  1511.                     if (c0 == 'B') *rpromote = BISHOP;
  1512.                     if (c0 == 'R') *rpromote = ROOK;
  1513.                     if ((c0 == 'N') || (c0 == 'B') || (c0 == 'R') || (c0 == 'Q'))
  1514.                         if (++numUsed <= lastChar)
  1515.                             c0 = cptr[numUsed];
  1516.                 }
  1517.             }
  1518.         }
  1519.     }
  1520.     if (c0 == '+') {
  1521.          check = true;
  1522.         if (++numUsed <= lastChar) c0 = cptr[numUsed];
  1523.     }
  1524.  
  1525.     for (numMatch = 0, j = 0; j < 2; ++j) {
  1526.         for (i = 0; i < numLglMoves; ++i) {
  1527.             f = (**lglMoves)[i].moveFrom;
  1528.             t = (**lglMoves)[i].moveTo;
  1529.  
  1530.             if (to >= START_IBNDS) {            /* If we have a fully formed to...               */
  1531.                 if (to != t) continue;            /* If to is different than this move, next move. */
  1532.             }
  1533.             else {
  1534.                 if (to) {
  1535.                     piece = (*frHndl)->doc.theBoard[t];
  1536.                     if (piece < 0) piece = -piece;
  1537.                     if (to <= BK)
  1538.                         if (piece > BK)
  1539.                             piece -= KSIDEPIECE;
  1540.                     if (piece != to) continue;
  1541.                 }
  1542.                 if ((!to) && (toRow == -1) && (toCol == -1)) continue;
  1543.                 r = (t - START_IBNDS) / 10;
  1544.                 c = t - START_IBNDS - 10 * r;
  1545.                 if (toRow == -1) r = -1;
  1546.                 if (toCol == -1) c = -1;
  1547.                     if (
  1548.                     (toRow != r) ||
  1549.                     ((toCol != c) && (toCol2 != c))
  1550.                 ) continue;
  1551.                 if (take) {
  1552.                     k = (**lglMoves)[i].moveTo;
  1553.                     if (!(*frHndl)->doc.theBoard[k]) continue;
  1554.                 }
  1555.             }
  1556.  
  1557.             if (from >= START_IBNDS) {
  1558.                 if (from == f) {
  1559.                     if (!j) ++numMatch;
  1560.                     else {
  1561.                         if (numMatch < 2) break;
  1562.                         if (MoveCausesCheck(frHndl, f, t) == check) break;
  1563.                     }
  1564.                 }
  1565.                 continue;
  1566.             }
  1567.             piece = (*frHndl)->doc.theBoard[f];
  1568.             if (piece < 0) piece = -piece;
  1569.             if (from <= BK)
  1570.                 if (piece > BK)
  1571.                     piece -= KSIDEPIECE;
  1572.             if (piece == from) {
  1573.                 r = (f - START_IBNDS) / 10;
  1574.                 c = f - START_IBNDS - 10 * r;
  1575.                 if (fromRow == -1) r = -1;
  1576.                 if (fromCol == -1) c = -1;
  1577.                 if (
  1578.                     (fromRow == r) &&
  1579.                     ((fromCol == c) || (fromCol2 == c))
  1580.                 ) {
  1581.                     if (!j) ++numMatch;
  1582.                     else {
  1583.                         if (numMatch < 2) break;
  1584.                         if (MoveCausesCheck(frHndl, f, t) == check) break;
  1585.                     }
  1586.                 }
  1587.             }
  1588.         }
  1589.     }
  1590.  
  1591.     if (i < numLglMoves) {
  1592.         *rfrom = (**lglMoves)[i].moveFrom;
  1593.         *rto   = (**lglMoves)[i].moveTo;
  1594.     };
  1595.  
  1596.     return(numUsed);
  1597. }
  1598.  
  1599.  
  1600.  
  1601. /*****************************************************************************/
  1602.  
  1603.  
  1604.  
  1605. Boolean    MoveCausesCheck(FileRecHndl game, short from, short to)
  1606. {
  1607.     short            numGameMoves, color, check;
  1608.     Boolean            docDirty;
  1609.     GameListHndl    gameMoves;
  1610.     long            size;
  1611.  
  1612.     gameMoves    = (*game)->doc.gameMoves;
  1613.     numGameMoves = (*game)->doc.numGameMoves;
  1614.     docDirty     = (*game)->fileState.docDirty;
  1615.  
  1616.     SetHandleSize((Handle)gGenMovesHndl, size = GetHandleSize((Handle)gameMoves));
  1617.     BlockMove(*(Handle)gameMoves, *(Handle)gGenMovesHndl, size);
  1618.     (*game)->doc.gameMoves = gGenMovesHndl;            /* Protect the game moves list. */
  1619.  
  1620.     color = (WhosMove(game) ^ 1);                        /* Who's move it is. */
  1621.  
  1622.     MakeMove(game, from, to, QUEEN);
  1623.     check = SquareAttacked(game,
  1624.         (*game)->doc.king[color].kingLoc, color);
  1625.     UnmakeMove(game);
  1626.  
  1627.     (*game)->doc.gameMoves      = gameMoves;
  1628.     (*game)->doc.numGameMoves   = numGameMoves;
  1629.     (*game)->fileState.docDirty = docDirty;
  1630.         /* Restore things the way we were.  We are done with MakeMove services. */
  1631.  
  1632.     if (check) return(true);
  1633.     else       return(false);
  1634. }
  1635.  
  1636.  
  1637.  
  1638.